package br.com.scaled.view;

import br.com.scaled.audio.AudioAnalyser;
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class ControladorView extends SurfaceView implements SurfaceHolder.Callback {

	private static final String TAG = "controlador";
	
	private SurfaceHolder surfaceHolder = null;
	private AudioAnalyser audioAnalyser = null;
	private ThreadTicker ticker = null;
	private Note nota = null;
	
	public ControladorView(Context context) {
		super(context);
		init(context);
	}
	
	public ControladorView(Context context, AttributeSet atts){
		super(context, atts);
		init(context);
	}
	
	private void init(Context app){
		surfaceHolder = getHolder();
		surfaceHolder.addCallback(this);
        
		audioAnalyser = new AudioAnalyser();
		nota = audioAnalyser.getNote();
	}
	
	public void onStart(){
		Log.i(TAG, "onStart");
		audioAnalyser.appStart();
	}
	
	public void onPause(){
		stopRun();
	}
	
	public void onStop(){
		Log.i(TAG, "onStop()");
		
		onPause();
		
		try{
			audioAnalyser.appStop();
		}catch(Exception e){
			
		}
	}
	
	public void setSampleRate(int sampleRate){
		audioAnalyser.setSampleRate(sampleRate);
	}
	
	public void setBlockSize(int blockSize){
		audioAnalyser.setBlockSize(blockSize);
	}
	
	public void setDecimation(int decimateRate){
		audioAnalyser.setDecimation(decimateRate);
	}

	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
		nota.setSize(format, width, height);
		startRun();
	}

	
	public void surfaceCreated(SurfaceHolder holder) {
	}

	public void surfaceDestroyed(SurfaceHolder holder) {
		stopRun();
	}
	
	private void startRun(){
		synchronized (surfaceHolder) {
			try{
				audioAnalyser.measureStart();
			}catch(Exception e){
				e.printStackTrace();
			}
			
			if(ticker != null && ticker.isAlive()){
				ticker.kill(); 
			}
			Log.i(TAG, "set running: start ticker");
			ticker = new ThreadTicker();
		}
	}
	
	private void stopRun(){
		ThreadTicker tTicker = null;
		synchronized (surfaceHolder) {
			tTicker = ticker;
		}
		if(tTicker != null && tTicker.isAlive()){
			if(Thread.currentThread() == ticker){
				tTicker.kill();
			}else {
				tTicker.killAndWait();
			}
		}
		synchronized (surfaceHolder) {
			ticker = null;
		}
		
		try{
			audioAnalyser.measureStop();
		}catch (Exception e){
			e.printStackTrace();
		}
		
	}
	
	private void tick(){
		try{
			long now = System.currentTimeMillis();
			audioAnalyser.doUpdate(now);
			
			refreshScreen(now);
		}catch (Exception e){
			e.printStackTrace();
		}
	}
	
	private void refreshScreen(long now){
		Canvas canvas = null;
		try{
			canvas = surfaceHolder.lockCanvas(null);
			synchronized (surfaceHolder) {
				nota.draw(canvas, now);
			}
		} finally {
			if(canvas != null){
				surfaceHolder.unlockCanvasAndPost(canvas);
			}
		}
	}
	
	
	
	/**
	 * Thread-based ticker class.  This may be faster than LoopTicker.
	 */
	private class ThreadTicker  extends Thread {

	    // Flag used to terminate this thread -- when false, we die.
	    private boolean enable = false;
		
	    // Constructor -- start at once.
	    private ThreadTicker() {
	        super("Surface Runner");
	        Log.v(TAG, "ThreadTicker: start");
	        enable = true;
	        start();
	    }

	    // Stop this thread.  There will be no new calls to tick() after this.
		public void kill() {
	        Log.v(TAG, "ThreadTicker: kill");
	        
	        enable = false;
	    }

	    // Stop this thread and wait for it to die.  When we return, it is
	    // guaranteed that tick() will never be called again.
	    // 
	    // Caution: if this is called from within tick(), deadlock is
	    // guaranteed.
		public void killAndWait() {
	        Log.v(TAG, "ThreadTicker: killAndWait");
	        
	        if (Thread.currentThread() == this)
	        	throw new IllegalStateException("ThreadTicker.killAndWait()" +
	        								    " called from ticker thread");

	        enable = false;

	        // Wait for the thread to finish.  Ignore interrupts.
	        if (isAlive()) {
	            boolean retry = true;
	            while (retry) {
	                try {
	                    join();
	                    retry = false;
	                } catch (InterruptedException e) {
	                	e.printStackTrace();
	                }
	            }
	            Log.v(TAG, "ThreadTicker: killed");
	        } else {
	            Log.v(TAG, "Ticker: was dead");
	        }
	    }

	    // Run method for this thread -- simply call tick() a lot until
	    // enable is false.
	    @Override
	    public void run() {
	        while (enable) {
	            tick();
	            
//                if (animationDelay != 0) try {
//                    sleep(animationDelay);
//                } catch (InterruptedException e) { }
	        }
	    }
	    
	}
	
	
}
